package packetCap.UI;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

import jpcap.NetworkInterface;
import jpcap.packet.ARPPacket;
import jpcap.packet.ICMPPacket;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;
import jpcap.packet.UDPPacket;
import packetCap.CapPacket.myCaptor;
import packetCap.CapPacket.myPacket;

public class UI extends JFrame{
	private JComboBox devicesListBox;
	private JButton startBtn;
	private JButton stopBtn;
	private JTable	packetTab;
	private JScrollPane jspForTab;
	private JScrollPane jspForTA;
	private JTextArea showDataArea;
	private JCheckBox tcpCb,udpCb,arpCb,ipCb,icmpCb;
	
	private String comboString;
	private String[] columns = {"id","protocal","src_ip","dst_ip","len"};
	private String[][] data = {{"1","tcp","192.168.0.23","192.168.0.1","88"}};
	private volatile DefaultTableModel model = new DefaultTableModel(data,columns);
	private volatile myCaptor cap;
	private volatile String[] wantedProtocal = new String [5];
	private volatile boolean ipFlag = true;
	private volatile boolean arpFlag = true;
	private volatile boolean icmpFlag = true;
	private volatile boolean tcpFlag = true;
	private volatile boolean udpFlag = true;
	private volatile Map<String,ArrayList<myPacket>> packetMap;
	
	
	private Thread worker = null;
	
	public UI(){

		super("packetCap");
		wantedProtocal[0] = "ip";
		wantedProtocal[1] = "arp";
		wantedProtocal[2] = "icmp";
		wantedProtocal[3] = "tcp";
		wantedProtocal[4] = "udp";
		packetMap = new HashMap<String, ArrayList<myPacket>>();
		packetMap.put("ARP", new ArrayList<myPacket>());
		packetMap.put("ICMP",new ArrayList<myPacket>());
		packetMap.put("TCP",new ArrayList<myPacket>());
		packetMap.put("UDP",new ArrayList<myPacket>());
		cap = new myCaptor(packetMap);
	}



	public void paintUI(){
		
		
		super.setSize(800,700);
		super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		centered(this);
		this.setLayout(null);

		
		devicesListBox = new JComboBox();
		devicesListBox.setBounds(new Rectangle(30,20,500,20));
		devicesListBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				comboString = ((JComboBox)e.getSource()).getSelectedItem().toString();
			}
		});
		for(NetworkInterface ni:cap.getDevices()){
			devicesListBox.addItem(ni.name);
		}
		this.add(devicesListBox);
		
		startBtn = new JButton("start");
		startBtn.setBounds(new Rectangle(560,20,80,20));
		startBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				stopBtn.setEnabled(true);
				startBtn.setEnabled(false);
				enableAllCheckBox();
				disableAllCheckBox();
				cap.setTargetDeviceName(comboString);
				cap.initCaptor();
				cap.setStartFlag(true);
				cap.setTab(packetTab);
				cap.setWantedProtocal(wantedProtocal);
				
				if(worker == null){
					worker = new Thread(new Runnable() {
						@Override
						public void run() {
							cap.begin();
						}
					});
				}
				worker.start();
				
			}
		});
		this.add(startBtn);
		
		stopBtn = new JButton("stop");
		stopBtn.setEnabled(false);
		stopBtn.setBounds(new Rectangle(670,20,80,20));
		stopBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				startBtn.setEnabled(true);
				stopBtn.setEnabled(false);
				cap.setStartFlag(false);
				worker = null;
				enableAllCheckBox();
			}
		});
		this.add(stopBtn);
		
		model.removeRow(0);
		packetTab = new JTable(model);
		jspForTab = new JScrollPane(packetTab);
		packetTab.setFillsViewportHeight(true);
		jspForTab.setBounds(30,80,750,300);
		ListSelectionModel lsm = packetTab.getSelectionModel();
		lsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		lsm.addListSelectionListener(new ListSelectionListener() {
			
			@Override
			public void valueChanged(ListSelectionEvent e) {
				
				if(!e.getValueIsAdjusting()){
					return;
				}
				
				packetTab.setEnabled(false);
				disableAllCheckBox();
				myPacket  tempMyPacket = null ;
				Packet p;
				int id;
				String proto;
				String data = "default";
				id = Integer.parseInt((String) packetTab.getValueAt(packetTab.getSelectedRow(), 0));
				proto = (String) packetTab.getValueAt(packetTab.getSelectedRow(), 1);
				if(proto.equals("HTTP")){
					proto = "TCP";
				}
				if(proto.equals("SSDP")){
					proto = "UDP";
				}
				for(myPacket mp:packetMap.get(proto)){
					if(mp.id == id){
						tempMyPacket = mp;
						break;
					}
				}
				
				p = tempMyPacket.p;
				if(p instanceof IPPacket && ((IPPacket)p).version == 4){
					IPPacket ip = (IPPacket)p;
					
					try {
						switch (ip.protocol) {
						case 1:
							ICMPPacket icmpPacket = (ICMPPacket)ip;
							data = new String(icmpPacket.data,"UTF-8");
							break;

						case 6:
							TCPPacket tcpPacket = (TCPPacket)ip;
							String tcpInfo = "src_port="+tcpPacket.src_port+"\tdst_port="+tcpPacket.dst_port+"\nack_num="+tcpPacket.ack_num+"\t";
							tcpInfo = tcpInfo+"sequence="+tcpPacket.sequence+"\n"+"flag:\n";
//							tcpInfo = tcpInfo+"fin="+tcpPacket.fin+"\tpsh="+tcpPacket.psh+"\trst="+tcpPacket.rst+"\tsyn="+tcpPacket.syn+"\turg="+tcpPacket.urg+"\tack="+tcpPacket.ack;
							if(tcpPacket.ack){
								tcpInfo = tcpInfo +"[ack]\t";
							}
							if(tcpPacket.syn){
								tcpInfo = tcpInfo +"[syn]\t";
							}
							if(tcpPacket.urg){
								tcpInfo = tcpInfo +"[urg]\t";
							}
							if(tcpPacket.psh){
								tcpInfo = tcpInfo +"[psh]\t";
							}
							if(tcpPacket.rst){
								tcpInfo = tcpInfo +"[rst]\t";
							}
							if(tcpPacket.fin){
								tcpInfo = tcpInfo +"[fin]\t";
							}
							tcpInfo = "<============about head===============>\n"+tcpInfo+"\n<============about data===============>\n";
							data = new String(tcpPacket.data,"UTF-8");
							data = tcpInfo + data;
							break;
						case 17:
							UDPPacket udpPacket = (UDPPacket)ip;
							String udpInfo = "src_port="+udpPacket.src_port+"\tdst_port="+udpPacket.dst_port;
							udpInfo = "<============about head===============>\n"+udpInfo+"\n<============about data===============>\n";
							data = new String(udpPacket.data,"UTF-8");
							data = udpInfo + data;
							break;

						}
					} catch (UnsupportedEncodingException e1) {
						e1.printStackTrace();
					}
					
				}else if(p instanceof ARPPacket){
					ARPPacket arpPacket = (ARPPacket)p;
					try {
						data = new String(arpPacket.data,"UTF-8");
					} catch (UnsupportedEncodingException e1) {
						e1.printStackTrace();
					}
					
				}
				showDataArea.setText(data);
				if(!cap.isStartFlag()){
					enableAllCheckBox();
				}
				packetTab.setEnabled(true);
				
			}
		});
		this.add(jspForTab);
		
		ipCb = new JCheckBox();
		arpCb = new JCheckBox();
		icmpCb = new JCheckBox();
		tcpCb = new JCheckBox();
		udpCb = new JCheckBox();
		ipCb.setSelected(true);
		arpCb.setSelected(true);
		icmpCb.setSelected(true);
		tcpCb.setSelected(true);
		udpCb.setSelected(true);
		ipCb.setText("IP");
		arpCb.setText("ARP");
		icmpCb.setText("ICMP");
		tcpCb.setText("TCP");
		udpCb.setText("UDP");
		ipCb.setBounds(30,385,60,20);
		arpCb.setBounds(100,385,60,20);
		icmpCb.setBounds(170,385,60,20);
		tcpCb.setBounds(240,385,60,20);
		udpCb.setBounds(310,385,60,20);
		disableAllCheckBox();
		
		ipCb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				boolean tempState = ipFlag;
				if(tempState){
					icmpCb.setSelected(false);
					tcpCb.setSelected(false);
					udpCb.setSelected(false);
					wantedProtocal[0] = "";
					wantedProtocal[2] = "";
					wantedProtocal[3] = "";
					wantedProtocal[4] = "";
				}else{
					icmpCb.setSelected(true);
					tcpCb.setSelected(true);
					udpCb.setSelected(true);
					wantedProtocal[0] = "ip";
					wantedProtocal[2] = "icmp";
					wantedProtocal[3] = "tcp";
					wantedProtocal[4] = "udp";
				}
				ipFlag = ipCb.isSelected();
				icmpFlag = icmpCb.isSelected();
				tcpFlag = tcpCb.isSelected();
				udpFlag = udpCb.isSelected();
				
				refreshData((DefaultTableModel)packetTab.getModel());
			}
		});
		
		arpCb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
//				stopBtn.doClick();
				boolean tempState = arpFlag;
				if(tempState){
					wantedProtocal[1] = "";
				}else{
					wantedProtocal[1] = "arp";
				}
				arpFlag = arpCb.isSelected();
				
				refreshData((DefaultTableModel)packetTab.getModel());
			}
		});
		
		icmpCb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				boolean tempState = icmpFlag;
				if(tempState){
					ipCb.setSelected(false);
					wantedProtocal[0] = "";
					wantedProtocal[2] = "";
				}else{
					wantedProtocal[2] = "icmp";
					if(icmpCb.isSelected()&&udpCb.isSelected()&&tcpCb.isSelected()){
						ipCb.setSelected(true);
						wantedProtocal[0] = "ip";
					}
				}
				icmpFlag = icmpCb.isSelected();
				ipFlag = ipCb.isSelected();
				refreshData((DefaultTableModel)packetTab.getModel());
			}
		});
		
		tcpCb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				boolean tempState = tcpFlag;
				if(tempState){
					ipCb.setSelected(false);
					wantedProtocal[0] = "";
					wantedProtocal[3] = "";
				}else{
					wantedProtocal[3] = "tcp";
					if(icmpCb.isSelected()&&udpCb.isSelected()&&tcpCb.isSelected()){
						ipCb.setSelected(true);
						wantedProtocal[0] = "ip";
					}
				}
				tcpFlag = tcpCb.isSelected();
				ipFlag = ipCb.isSelected();
				
				refreshData((DefaultTableModel)packetTab.getModel());
			}
		});
		
		udpCb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				boolean tempState = udpFlag;
				if(tempState){
					ipCb.setSelected(false);
					wantedProtocal[0] = "";
					wantedProtocal[4] = "";
				}else{
					wantedProtocal[4] = "udp";
					if(icmpCb.isSelected()&&udpCb.isSelected()&&tcpCb.isSelected()){
						ipCb.setSelected(true);
						wantedProtocal[0] = "ip";
					}
				}
				udpFlag = udpCb.isSelected();
				ipFlag = ipCb.isSelected();
				refreshData((DefaultTableModel)packetTab.getModel());
			}
		});
		
		
		this.add(ipCb);
		this.add(arpCb);
		this.add(icmpCb);
		this.add(tcpCb);
		this.add(udpCb);
		
		showDataArea = new JTextArea();
		jspForTA = new JScrollPane(showDataArea);
		jspForTA.setBounds(30, 410, 750, 200);
		this.add(jspForTA);
		
		super.setVisible(true);
		
	}
	public void centered(Container container) {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension screenSize = toolkit.getScreenSize();
        int w = container.getWidth();
        int h = container.getHeight();
        container.setBounds((screenSize.width - w) / 2,
                (screenSize.height - h) / 2, w, h);
    }
	public void printStringArray(String[] tar){
		for(String s:tar){
			System.out.print(s+" ");
		}
		System.out.println();
	}
	private void disableAllCheckBox(){
		ipCb.setEnabled(false);
		arpCb.setEnabled(false);
		icmpCb.setEnabled(false);
		udpCb.setEnabled(false);
		tcpCb.setEnabled(false);
	}
	private void enableAllCheckBox(){
		ipCb.setEnabled(true);
		arpCb.setEnabled(true);
		icmpCb.setEnabled(true);
		udpCb.setEnabled(true);
		tcpCb.setEnabled(true);
	}
	
	private void refreshData(DefaultTableModel model){
		ArrayList<ArrayList<String>> temp = new ArrayList<ArrayList<String>>(model.getDataVector().size());
		if(!wantedProtocal[1].equals("")){
			for(myPacket mp:packetMap.get("ARP")){
				ArrayList<String> tempElement = new ArrayList<String>();
				tempElement.add(mp.id+"");
				tempElement.add(mp.protocal);
				tempElement.add(mp.src_ip);
				tempElement.add(mp.dst_ip);
				tempElement.add(mp.len+"");
				temp.add(tempElement);
			}
		}
		if(!wantedProtocal[2].equals("")){
			for(myPacket mp:packetMap.get("ICMP")){
				ArrayList<String> tempElement = new ArrayList<String>();
				tempElement.add(mp.id+"");
				tempElement.add(mp.protocal);
				tempElement.add(mp.src_ip);
				tempElement.add(mp.dst_ip);
				tempElement.add(mp.len+"");
				temp.add(tempElement);
			}
		}
		if(!wantedProtocal[3].equals("")){
			for(myPacket mp:packetMap.get("TCP")){
				ArrayList<String> tempElement = new ArrayList<String>();
				tempElement.add(mp.id+"");
				tempElement.add(mp.protocal);
				tempElement.add(mp.src_ip);
				tempElement.add(mp.dst_ip);
				tempElement.add(mp.len+"");
				temp.add(tempElement);
			}
		}
		if(!wantedProtocal[4].equals("")){
			for(myPacket mp:packetMap.get("UDP")){
				ArrayList<String> tempElement = new ArrayList<String>();
				tempElement.add(mp.id+"");
				tempElement.add(mp.protocal);
				tempElement.add(mp.src_ip);
				tempElement.add(mp.dst_ip);
				tempElement.add(mp.len+"");
				temp.add(tempElement);
			}
		}
		Collections.sort(temp,new sortById());
		model.getDataVector().removeAllElements();
		for(ArrayList<String> list:temp){
			model.addRow(list.toArray());
		}
		
		
	}
	public String getComboString() {
		return comboString;
	}
}

class sortById implements Comparator<ArrayList<String>>{

	@Override
	public int compare(ArrayList<String> o1, ArrayList<String> o2) {
		
		return Integer.parseInt(o1.get(0))-Integer.parseInt(o2.get(0));
	}

}
